package com.tour.tour.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tour.tour.common.Response;
import com.tour.tour.dto.*;
import com.tour.tour.entity.User;
import com.tour.tour.mapper.UserMapper;
import com.tour.tour.service.UserService;
import com.tour.tour.utils.RegexUtil;
import com.tour.tour.utils.TokenUtil;
import com.tour.tour.utils.UserHolder;
import com.tour.tour.utils.VerifyCodeUtil;
import com.tour.tour.vo.LoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.tour.tour.utils.constant.RedisConstant.*;
import static com.tour.tour.utils.constant.SystemConstant.USERNAME_PREFIX;

/**
 * @author 76004
 * @apiNote
 * @date 2023/4/24 22:44
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    
    @Override
    public Response sendCode(String phone, HttpSession session) {
        // 1.校验手机号
        if (RegexUtil.isPhoneValid(phone)) {
            // 2.如果不符合，则返回错误信息
            return Response.error("手机号格式错误");
        }
        // 3.符合，产生验证码
        VerifyCodeDTO verifyCodeDTO = VerifyCodeUtil.getCode();
        // 返回的是验证码图片url
        String codeUrl = verifyCodeDTO.getCodeUrl();
        // 缓存的是验证码
        String code = verifyCodeDTO.getCode();
        // 4.保存验证码到 redis
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.SECONDS);
        // 5.发送验证码
        log.info("获取验证码成功，验证码：{}", code);
        // 6.返回成功
        VerifyCodeImgUrlDTO imgUrl = new VerifyCodeImgUrlDTO();
        imgUrl.setUrl(codeUrl);
        return Response.success(imgUrl);
    }

    @Override
    @Transactional
    public Response register(RegisterFormDTO registerForm, HttpSession session) {
        String password = registerForm.getPassword();
        if (RegexUtil.isPasswordValid(password)) {
            return Response.error("密码格式有误！");
        }
        // 1.校验手机号
        String phone = registerForm.getPhone();
        // 4.一致，根据手机号查询用户
        User user = query().eq("phone", phone).one();
        // 5.判断用户是否存在
        if (user == null) {
            // 6.不存在，创建新的用户并保存
            user = createUserWithPhone(phone, password);
        }
        user.setAvatar(registerForm.getAvatar());
        // 7.保存用户信息到Redis中
        String token = UUID.randomUUID().toString(true);
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.SECONDS);
        
        // 8.返回token
        return Response.success(token);
    }

    @Override
    public Response login(LoginFormDTO loginForm, HttpSession session) {
        // 1.验证密码
        String password = loginForm.getPassword();
        if (RegexUtil.isPasswordValid(password)) {
            return Response.error("密码格式有误！");
        }
        // 2.验证手机号
        String phone = loginForm.getPhone();
        // 4.根据手机号查询用户
        User user = query().eq("phone", phone).one();
        // 5.判断用户是否存在
        if (user == null) {
            // 6.不存在，则报错返回注册
            return Response.error("用户不存在，请返回注册！");
        }
        if (!password.equals(user.getPassword())) {
            // 7.密码不一致，则报错密码错误
            return Response.error("密码错误！");
        }
        // 8.登录成功
//        String token = UUID.randomUUID().toString(true);
        String token = TokenUtil.generateToken(user.getPhone());
        System.out.println(token);
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.SECONDS);
        
        return Response.success(token);
    }

    @Override
    @Transactional
    public Response<LoginVO> forgotPassword(RegisterFormDTO forgotForm, HttpSession session) {
        String password = forgotForm.getPassword();
        if (RegexUtil.isPasswordValid(password)) {
            return Response.error("密码格式有误！");
        }
        // 1.校验手机号
        String phone = forgotForm.getPhone();
        if (RegexUtil.isPhoneValid(phone)) {
            // 2.如果不符合，则返回错误信息
            return Response.error("手机号格式错误！");
        }
        // 3.从redis获取验证码并校验
        String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);
        String code = forgotForm.getCode();

        if (code == null || !cacheCode.equals(code)) {
            // 不一致，则报错
            return Response.error("验证码错误！");
        }
        // 4.一致，根据手机号查询用户
        User user = query().eq("phone", phone).one();
        // 5.判断用户是否存在
        if (user == null) {
            // 6.不存在，则报错用户不存在
            return Response.error("用户不存在！");
        }
        // 更新密码和时间
        user.setPassword(password);
        user.setUpdateTime(LocalDateTime.now());
        // 更新信息到数据库
        save(user);
        // 7.保存用户信息到Redis中
        String token = UUID.randomUUID().toString(true);
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.SECONDS);
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setAvatar(user.getAvatar());

        // 8.返回token
        return Response.success(token);
    }

    private User createUserWithPhone(String phone, String password) {
        User user = new User();
        user.setPhone(phone);
        user.setPassword(password);
        user.setUsername(USERNAME_PREFIX + RandomUtil.randomString(10));
        save(user);
        return user;
    }

    @Override
    public Response sign() {
        return null;
    }

    @Override
    public Response signCount() {
        return null;
    }
}
